package org.openstock.impl.def.core.factory;

import java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openstock.design.Registerable;
import org.openstock.impl.def.core.ui.swing.widget.FileMenu;

@SuppressWarnings("unchecked")
public abstract class Factory {

	private static final Map<Class<?>,WeakReference<?>> map = new HashMap<Class<?>,WeakReference<?>>();
	private static Class<?>[] classes;
	
	public static void main(String[] args){
		List<Registerable> list = getImplimentations(Registerable.class);
		for(Registerable r : list){
			System.out.println(r);
		}
	}
	
	public static <T> List<T> getImplimentations(Class<T> clazz){
		if(classes == null){
			classes = new ClassPathScanner().getClassesInPackage("org.openstock.impl.def", null);
		}
		List<T> list = new ArrayList<T>();
		for(Class<?> c : classes){
			if(!c.isAnnotation()
					&& !c.isArray()
					&& !c.isEnum()
					&& !c.isInterface()
					&& !c.isPrimitive()
					&& !Modifier.isAbstract(c.getModifiers())
					&& clazz.isAssignableFrom(c)){
				list.add((T)getSingleton(c));
			}
		}
		return list;
	}
	
	public static <T> T getSingleton(Class<T> clazz){
		WeakReference<T> ref = (WeakReference<T>)map.get(clazz);
		T instance;
		try {
			if(ref == null || ref.get() == null){
				instance = clazz.newInstance();
				map.put(clazz, new WeakReference<T>(instance));
			}else{
				instance = ref.get();
			}
		} catch (Exception e) {
			instance = null;
			e.printStackTrace();
		}
		return instance;
	}
	
	
	
	public static <T> T getSingleton(Class<T> clazz, Class<?>[] parameterTypes, Object[] parameters){
		WeakReference<T> ref = (WeakReference<T>)map.get(clazz);
		T instance;
		try {
			if(ref == null || ref.get() == null){
				instance = clazz.getConstructor(parameterTypes).newInstance(parameters);
				map.put(clazz, new WeakReference<T>(instance));
			}else{
				instance = ref.get();
			}
		} catch (Exception e) {
			instance = null;
			e.printStackTrace();
		}
		return instance;
	}
	
	
	public static <T> T getPrototype(Class<T> clazz){
		T instance = null;
		try {
				instance = clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return instance;
	}
	
	public static <T> T getPrototype(Class<T> clazz, Class<?>[] parameterTypes, Object[] parameters){
		T instance = null;
		try {
				instance = clazz.getConstructor(parameterTypes).newInstance(parameters);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return instance;
	}
	
	
}
